#define _CRT_SECURE_NO_WARNINGS 1
#include "string.h"

str::String::String(const char* str)
	: _size(strlen(str))
	, _capacity(_size)
{
	_str = new char[_size + 1];
	strcpy(_str, str);
}

void str::String::swap(str::String& s)
{
	std::swap(_str, s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

str::String::~String()
{
	delete[] _str;
	_str = nullptr;
	_size = _capacity = 0;
}

char& str::String::operator[](size_t pos)
{
	assert(pos < _size);
	
	return _str[pos];
}

const char& str::String::operator[](size_t pos) const
{
	assert(pos < _size);

	return _str[pos];
}

ostream& str::operator<<(ostream& out, const str::String& s)
{
	for (auto ch : s)
	{
		out << ch;
	}

	return out;
}

str::String::iterator str::String::begin()
{
	return _str;
}

str::String::iterator str::String::end()
{
	return _str + _size;
}

str::String::const_iterator str::String::begin() const
{
	return _str;
}

str::String::const_iterator str::String::end() const
{
	return _str + _size;
}

size_t str::String::size() const
{
	return _size;
}

size_t str::String::capacity() const
{
	return _capacity;
}

const char* str::String::c_str() const
{
	return _str;
}

void str::String::clear()
{
	_str[0] = '\0';
	_size = 0;
}

void str::String::reserve(size_t n)
{
	if (n > _size)
	{
		char* temp = new char[n + 1];
		strcpy(temp, _str);
		delete[] _str;
		_str = temp;

		_capacity = n;
	}
}

void str::String::push_back(char n)
{
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}

	_str[_size] = n;
	_size++;
	_str[_size] = '\0';
}

void str::String::append(const char* str)
{
	size_t length = strlen(str);
	if (length + _size > _capacity)
	{
		reserve(_size + length);
	}

	strcpy(_str + _size, str);
	_size += length;
}

void str::String::insert(size_t pos, char ch)
{
	assert(pos <= _size);

	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}

	int end = (size_t)_size + 1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		end--;
	}
	_str[end] = ch;
	_size++;
}

void str::String::insert(size_t pos, char* s)
{
	assert(pos <= _size);
	size_t length = strlen(s);
	if (_size + length > _capacity)
	{
		reserve(_size + length);
	}
	
	int end = (int)_size;
	while (end >= (int)pos)
	{
		_str[end + length] = _str[end];
		end--;
	}

	strncpy(_str + pos, s, length);
	_size += length;
}

str::String& str::String::operator+=(const char* s)
{
	append(s);
	return *this;
}

str::String& str::String::operator+=(char ch)
{
	push_back(ch);
	return *this;
}

bool str::String::operator<(const str::String& s) const
{
	return strcmp(_str, s._str) < 0;
}

bool str::String::operator<=(const str::String& s) const
{
	return _str < s._str || _str == s._str;
}

bool str::String::operator!=(const str::String& s) const
{
	return !(_str == s._str);
}

bool str::String::operator==(const str::String& s) const
{
	return strcmp(_str, s._str) == 0;
}

bool str::String::operator>(const str::String& s) const
{
	return !(_str <= s._str);
}

bool str::String::operator>=(const str::String& s) const
{
	return !(_str < s._str);
}

str::String& str::String::operator=(str::String tmp)
{
	swap(tmp);
	return *this;
}